﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using FinPlusCommon;
using u = FinPlusUtility.Utility;
using log = Logger.Logger;

namespace FinPlusWPFControls
{
    public partial class FinPlusValueQuotePopup: FinPlusControl
    {
        public override string Id { get; set; }
        public override string[] States { get { return new string[] { }; } }
        public override string[] TestStates { get { return new string[] { "ModelTest", "ViewTest", "IsValid" }; } }
        public override IFinPlusFunctions Model { get { return null; } }
        public override string ModelTest { get { return ModelToString(); } }
        public override bool IsValid { get; set; }

        public string ViewTest { get { return ToString(); } }

        public new bool IsEnabled { get; private set; }
        public string QuoteSource { get; private set; }
        public string Instrument { get; private set; }
        public DateTime SettlementDate { get; private set; }
        public string Book { get; private set; }
        public string BuySell { get; private set; }
        public double Size { get; private set; }
        public double Quote { get; private set; }
        public string Counterparty { get; private set; }
        public Action Close { get; set;}
        public Action DragMove { get; set; }

        private enum Params { QuoteSource, Instrument, RateType, Rate, Counterparty, Settle, Book, BuySell, Size, Quote, FunctionName, Id, ClientGuid }
        private DispatcherTimer _timer;
        private TimeSpan _time = TimeSpan.FromSeconds(10);
        private Action<string> _callback;
        private IFinPlusFuncDynamic _instrument;
        private IFinPlusFunction _quote;
        private string _reply;
        private static int _angle, _angleChange = 30, _radius = 100;

        //construct
        public FinPlusValueQuotePopup(IFinPlusFunction quote, IFinPlusFuncDynamic instrument, string id, Action<string> callback, string reply, string clientGuid)
        {
            InitializeComponent();
            DataContext = this;
            IsEnabled = true;
            countDown.Text = _time.ToString("c");
            _quote = quote;
            _quote[Params.ClientGuid.ToString()] = clientGuid;
            _instrument = instrument;
            _callback = callback;
            _reply = reply;
            Id = id;
            Initialise();
            IsValid = true;
        }

        //common control interface
        public override void Dock(object control, string dock)
        {
            IsValid = false;
            throw new NotImplementedException();
        }

        public override void Initialise()
        {
            try
            {
                QuoteSource = _quote[Params.QuoteSource.ToString()].ToString();
                Instrument = _quote[Params.Instrument.ToString()].ToString();
                SettlementDate = (DateTime)_quote.Value(Params.Settle.ToString());
                Book = _quote[Params.Book.ToString()].ToString();
                Quote = (double)_quote.Value(Params.Quote.ToString());
                Counterparty = _quote[Params.Counterparty.ToString()].ToString();
                Size = (double)_quote.Value(Params.Size.ToString());

                if (_quote[Params.RateType.ToString()].ToString().Equals(Params.Rate.ToString()))
                    tQuote.SetBinding(FinPlusValueShiftTextBox.TextProperty, new Binding(Params.Quote.ToString()) { StringFormat = "{0:P2}" });
                else
                    tQuote.SetBinding(FinPlusValueShiftTextBox.TextProperty, new Binding(Params.Quote.ToString()));

                var command = u.EnumTryParse<Commands>(_quote[Params.FunctionName.ToString()].ToString(), Commands.Exception);
                var buySell = _quote[Params.BuySell.ToString()].ToString();
                BuySell = command == Commands.QuoteExecutePublish ? buySell : buySell.Equals("Buy") ? "Sell" : "Buy";

                switch (command)
                {
                    case Commands.Quote: StartQuoteExecute(); break;
                    case Commands.QuoteMissed: StartQuoteMissed(); break;
                    case Commands.QuoteDecline: StartQuoteDecline(); break;
                    case Commands.QuoteAccept: StartQuoteAccept(); break;
                    case Commands.QuoteExecutePublish: StartQuoteExecutePublish(); break;
                    case Commands.Exception: break;
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void CommandRouter(IFinPlusFunction func) 
        {
            try
            {
                CaptureCommand(func);

                SaveAudit(func.Name, new IFinPlusFunction[] { func, _quote });

                switch ((Commands)Enum.Parse(typeof(Commands), func.Name, true))
                {
                    case Commands.QuoteAcceptPublish: QuoteAcceptPublish(); break;
                    case Commands.QuoteDeclinePublish: QuoteDeclinePublish(); break;
                    case Commands.QuoteExecute: QuoteExecute(); break;
                    case Commands.QuoteClose: QuoteClose(); break;
                    case Commands.QuoteAccept: QuoteAccept(); break;
                    case Commands.QuoteDecline: QuoteDecline(); break;
                    case Commands.QuoteMissed: QuoteMissed(); break;
                    default: throw new Exception(string.Format("event not recognised {0}", func.Name));
                }
            }
            catch (Exception e)
            {
               IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void Dispose(){}

        //public
        public new string ToString()
        {
            return string.Format("{0}|{1}|{2}|{3}|{4}", titleText, buySellText, tQuote, quoteSourceText, bookText);
        }

        public string ModelToString()
        {
            return string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}", IsEnabled, QuoteSource, Instrument, Book, BuySell, Size, Quote, Counterparty);
        }

        public static void Show(IFinPlusFunction quote, IFinPlusFuncDynamic instrument, string id, string reply, string clientGuid)
        {
            var thread = new Thread(new ThreadStart(() =>
            {
                SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));

                var window = new Window {SizeToContent = SizeToContent.WidthAndHeight, WindowStyle = WindowStyle.None, ResizeMode = ResizeMode.NoResize };
                window.Content = new FinPlusValueQuotePopup(quote, instrument, id, null, reply, clientGuid) { DragMove = window.DragMove, Close = window.Close };
                OpenCentral(window);

                window.Closed += (sender, a) => Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
                Dispatcher.Run();
            }));

            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
        }

        public static void Show(IFinPlusFunction quote, string id, Action<string> callback, string clientGuid)
        {
            var window = new Window {SizeToContent = SizeToContent.WidthAndHeight, WindowStyle = WindowStyle.None, ResizeMode = ResizeMode.NoResize };
            window.Content = new FinPlusValueQuotePopup(quote, null, id, callback, null, clientGuid){DragMove = window.DragMove, Close = window.Close};
            OpenMouse(window);
        }

        //private

        private static void OpenCentral(Window window)
        {
            var p = new Point(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width / 2, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height / 2);
            _angle = (_angle + _angleChange) % 360;
            window.Left = _radius * Math.Cos(Math.PI * _angle / 180.0) + p.X;
            window.Top = _radius * Math.Sin(Math.PI * _angle / 180.0) + p.Y;
            window.Topmost = true;
            window.Show();
        }

        private static void OpenMouse(Window window)
        {
            var p = System.Windows.Forms.Control.MousePosition;
            window.Left = p.X - 300;
            window.Top = p.Y - 150;
            window.Topmost = true;
            window.Show();
        }

        private bool QuoteExecute()
        {

            _quote.Get(Params.FunctionName.ToString()).Set(_quote.Name = Commands.QuoteExecute.ToString());
            SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
            _callback.Invoke(_quote.ToString());
            StopTimer();
            Close.Invoke();
            return true;
        }

        private bool QuoteClose()
        {
            StopTimer();
            Close.Invoke();
            return true;
        }

        private bool QuoteMissed()
        {
            Close.Invoke();
            return true;
        }

        private bool QuoteDecline()
        {
            Close.Invoke();
            return true;
        }

        private bool QuoteAccept()
        {
            Close.Invoke();
            return true;
        }

        private bool QuoteAcceptPublish()
        {
            _quote.Get(Params.FunctionName.ToString()).Set(_quote.Name = Commands.QuoteAcceptPublish.ToString());
            _instrument.SetValue(_reply, _quote.ToString(), User, DateTime.Now);
            StopTimer();
            Close.Invoke();
            return true;
        }

        private bool QuoteDeclinePublish()
        {
            _quote.Get(Params.FunctionName.ToString()).Set(_quote.Name = Commands.QuoteDeclinePublish.ToString());
            _instrument.SetValue(_reply, _quote.ToString(), User, DateTime.Now);
            StopTimer();
            Close.Invoke();
            return true;
        }

        private void StartQuoteExecute()
        {
            bTraderExecute.Visibility = bTraderClose.Visibility = Visibility.Visible;
            if (GetPermission(Params.Instrument.ToString(), Params.Id.ToString(), Id).CanWrite)
                bTraderExecute.IsEnabled = bTraderClose.IsEnabled = true;

            StartTimer();
        }

        private void StartQuoteMissed()
        {
            bTraderMissed.Visibility = Visibility.Visible;
            bTraderMissed.IsEnabled = true;
        }

        private void StartQuoteAccept()
        {
            bVendorAccept.Visibility =  Visibility.Visible;
            bVendorAccept.IsEnabled = true;
        }

        private void StartQuoteDecline()
        {
            bVendorDecline.Visibility = Visibility.Visible;
            bVendorDecline.IsEnabled = true;
        }

        private void StartQuoteExecutePublish()
        {
            bTraderAccept.Visibility = bTraderDecline.Visibility = Visibility.Visible;
            if (GetPermission(Params.Instrument.ToString(), Params.Id.ToString(), Id).CanWrite)
                bTraderAccept.IsEnabled = bTraderDecline.IsEnabled = true;

            StartTimer();
        }

        private void StartTimer()
        {
            try
            {

                _timer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, delegate
                {
                    countDown.Text = _time.ToString("c");
                    if (_time <= TimeSpan.Zero)  Close.Invoke();
                    _time = _time.Add(TimeSpan.FromSeconds(-1));
                }, this.Dispatcher);
                _timer.Start();
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        private void StopTimer()
        {
            if(_timer !=null)
                _timer.Stop();
        }

        //cmds
        private new enum Commands { Quote, QuoteExecute, QuoteMissed, QuoteDecline, QuoteAccept, QuoteClose, QuoteAcceptPublish, QuoteDeclinePublish, QuoteExecutePublish, Exception }

        //events
        private void QuoteClose(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteClose.ToString(), Id, User)); }
        private void QuoteExecute(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteExecute.ToString(), Id, User)); }
        private void QuoteMissed(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteMissed.ToString(), Id, User)); }
        private void QuoteDecline(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteDecline.ToString(), Id, User)); }
        private void QuoteAccept(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteAccept.ToString(), Id, User)); }
        private void QuoteAcceptPublish(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteAcceptPublish.ToString(), Id, User)); }
        private void QuoteDeclinePublish(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.QuoteDeclinePublish.ToString(), Id, User)); }
        private void Title_MouseDown(object sender, MouseButtonEventArgs a){ DragMove.Invoke(); }
    }
}